﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace LinkUp
{
    /// <summary>
    /// 游戏类
    /// </summary>
    public class Game
    {
        /// <summary>
        /// 初始化新游戏
        /// </summary>
        public Game(bool isFull)
        {
            //生成游戏界面
            screen = new Grid();
            multiRan = new Random(DateTime.Now.Millisecond);
            xml = new XmlRW(AppDomain.CurrentDomain.BaseDirectory + "\\app.config");
            //设置游戏难度
            gLevel = (GameLevel)(6 + 2 * Convert.ToInt32(xml.GetValue("GameLevel")));
            //设置游戏皮肤
            screen.Skin = (GameSkin)(Convert.ToInt32(xml.GetValue("GameSkin")));
            //游戏块对齐方式
            //blockMode = (BlockChangeMode)(Convert.ToInt32(xml.GetValue("BlockMode")));
            blockMode = (BlockChangeMode)multiRan.Next(0, 6);
            screen.IsFullScrenn = isFull;
            screen.Create(gLevel);
            //默认值
            gTime = 10 * (int)gLevel - 40;
            preClick = -1;
            curClick = -1;
            remain = TotalGrid;
            totalScore = 0;
            multiple = 1;
            promptNum = 5;
            pause = 3;
            isPrompt = false;
            isPlaySound = true;
            InitSound();
            state = GameState.Play;
        }
        #region user function
        /// <summary>
        /// 处理鼠标点击事件
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns>-1: 选错 0: 消除 >0: 选择游戏块</returns>
        public int Click(float x, float y)
        {
            if (isPrompt)
            {
                screen.UnPrompt(screen.Finder.PathPointList);
                isPrompt = false;
            }
            x = x - screen.GridStartPos.X;
            y = y - screen.GridStartPos.Y;
            if (!screen.IsValidClick(x, y))
            {
                if (preClick != -1)
                {
                    multiple = (int)gLevel / 2 - 3;
                    return preClick;
                }
            }
            else
            {
                int index = screen.GetIndex(x, y);
                if (screen.Stat[index - 1] != 0)
                {
                    if (preClick == -1)
                    {
                        ChooseBlock(index);
                        return preClick;
                    }
                    else
                    {
                        if (preClick != index)
                        {
                            if (screen.GetBlock(preClick).BValue == screen.GetBlock(index).BValue)
                            {
                                if (screen.Finder.Execute(preClick, index))
                                {
                                    //消除游戏块
                                    EraseBlock(preClick, index);
                                    //游戏块自动对齐
                                    ChangeBlock(preClick, index);

                                    preClick = -1;
                                    remain -= 2;
                                    totalScore += multiple;
                                    multiple = multiRan.Next((int)gLevel / 2 - 3, 5 + (int)gLevel / 2 - 3);
                                    if (remain == 0)
                                    {
                                        promptNum += 1;
                                    }
                                    return 0;
                                }
                            }
                            multiple = (int)gLevel / 2 - 3;
                            UnChooseBlock();
                            ChooseBlock(index);
                            return preClick;
                        }
                    }
                }
                else
                {
                    if (preClick != -1)
                    {
                        multiple = (int)gLevel / 2 - 3;
                        return preClick;
                    }
                }
            }
            multiple = (int)gLevel / 2 - 3;
            return -1;
        }
        /// <summary>
        /// 游戏下一关
        /// </summary>
        public bool NextLevel()
        {
            if (gLevel != GameLevel.Hard)
            {
                gLevel = (GameLevel)((int)gLevel + 2);
                screen.Create(gLevel);
                remain = TotalGrid;
                multiple = multiple > (int)gLevel / 2 - 3 ? multiple : (int)gLevel / 2 - 3;
                gTime = 10 * (int)gLevel - 40;
                return true;
            }
            return false;
        }
        /// <summary>
        /// 判断是否死锁
        /// </summary>
        /// <returns>true:死锁; false:无死锁</returns>
        public bool IsDead()
        {
            for (int i = 0; i < TotalGrid; i++)
            {
                if (screen.Stat[i] > 0)
                {
                    for (int j = i + 1; j < TotalGrid; j++)
                    {
                        if (screen.Stat[j] == screen.Stat[i])
                        {
                            if (screen.Finder.Execute(i + 1, j + 1))
                            {
                                return false;
                            }
                        }
                    }
                }
            }
            return true;
        }
        /// <summary>
        /// 游戏提示
        /// </summary>
        public void Prompt()
        {
            if (promptNum > 0 && !isPrompt && !IsDead())
            {
                isPrompt = true;
                promptNum -= 1;
                screen.Prompt(screen.Finder.PathPointList);
            }
        }

        /// <summary>
        /// 自动消除
        /// </summary>
        public void AutoErase()
        {
            if (!IsDead())
            {
                EraseBlock(screen.GetIndex(screen.Finder.StartPosition), screen.GetIndex(screen.Finder.EndPosition));
                remain -= 2;
                totalScore += multiple;
                multiple = multiRan.Next((int)gLevel / 2 - 3, 5 + (int)gLevel / 2 - 3);
            }
            else
            {
                System.Threading.Thread.Sleep(1000);
                if (remain == 0)
                {
                    totalScore += 5 * this.gTime;
                    if (!NextLevel())
                    {
                        state = GameState.End;
                    }
                }
                else
                {
                    this.RefreshBlock();
                }
            }
            System.Threading.Thread.Sleep(100);
        }

        /// <summary>
        /// 自动完成
        /// </summary>
        public void AutoPlay()
        {
            while (state != GameState.End)
            {
                AutoErase();
            }
        }

        /// <summary>
        /// 显示路径，返回绘制路径后的图
        /// </summary>
        /// <param name="pList"></param>
        public Bitmap ShowPath(IList<Point> pList)
        {
            Bitmap b = screen.Map;
            Graphics g = Graphics.FromImage(b);
            foreach (Point p in pList)
            {
                screen.DrawDot(g, p.X, p.Y);
            }
            g.Dispose();
            return b;
        }

        /// <summary>
        /// 开始背景音乐
        /// </summary>
        public void StartPlayBack()
        {
            spBg.PlaySound();
        }

        /// <summary>
        /// 结束背景音乐
        /// </summary>
        public void StopPlayBack()
        {
            spBg.StopSound();
        }

        /// <summary>
        /// 选中块
        /// </summary>
        /// <param name="index"></param>
        public void ChooseBlock(int index)
        {
            preClick = index;
            screen.Choose(preClick);
            if (isPlaySound)
            {
                spSelect.PlaySound();
            }
        }

        /// <summary>
        /// 取消选中块
        /// </summary>
        /// <param name="index"></param>
        public void UnChooseBlock()
        {
            screen.UnChoose(preClick);
            preClick = -1;
        }

        /// <summary>
        /// 重新排列
        /// </summary>
        public void RefreshBlock()
        {
            while (IsDead())
            {
                screen.RefreshBlock();
                if (isPlaySound)
                {
                    spRefresh.PlaySound();
                }
            }
        }

        /// <summary>
        /// 消除游戏块
        /// </summary>
        /// <param name="pre"></param>
        /// <param name="cur"></param>
        public void EraseBlock(int pre, int cur)
        {
            screen.UnChoose(pre);
            screen.Erase(pre, cur);
            if (isPlaySound)
            {
                spErase.PlaySound();
            }
        }

        /// <summary>
        /// 报警
        /// </summary>
        public void Alarm()
        {
            if (isPlaySound)
            {
                spHint.PlaySound();
            }
        }

        /// <summary>
        /// 设置游戏全屏
        /// </summary>
        public void SetFullScreen()
        {
            if (!screen.IsFullScrenn)
            {
                screen.IsFullScrenn = true;
                //设置屏幕位置
                screen.SetScreen(gLevel);
                screen.Map = new Bitmap(screen.Map, screen.GWidth, screen.GHeight);
                screen.BackGround = new Bitmap(screen.BackGround, SystemInformation.PrimaryMonitorSize.Width - 120, SystemInformation.PrimaryMonitorSize.Height - 44);
                foreach (Block b in screen.Blocks)
                {
                    b.BWidth = (int)((double)screen.GWidth / (screen.HCount + 2) + 0.5) - 1;
                    b.BHeight = (int)((double)screen.GHeight / (screen.VCount + 2) + 0.5) - 1;
                    //b.Image = new Bitmap(b.Image, (int)((double)screen.GWidth / (screen.HCount + 2) + 0.5) - 1, (int)((double)screen.GHeight / (screen.VCount + 2) + 0.5) - 1);
                }
                //重绘界面
                screen.RefreshScreen();
                if (isPrompt)
                {
                    screen.Prompt(screen.Finder.PathPointList);
                }
                //else 
                //{
                //    if (screen.Finder.PathPointList.Count != 0)
                //    {
                //        screen.UnPrompt(screen.Finder.PathPointList);
                //    }
                //}
                if (preClick != -1)
                {
                    screen.Choose(preClick);
                }
            }
        }

        /// <summary>
        /// 取消游戏全屏
        /// </summary>
        public void SetNormal()
        {
            if (screen.IsFullScrenn)
            {
                screen.IsFullScrenn = false;
                //设置屏幕位置
                screen.SetScreen(gLevel);
                screen.Map = new Bitmap(screen.Map, screen.GWidth, screen.GHeight);
                screen.BackGround = new Bitmap(screen.BackGround, 800, 640);
                foreach (Block b in screen.Blocks)
                {
                    b.BWidth = (int)((double)screen.GWidth / (screen.HCount + 2) + 0.5) - 1;
                    b.BHeight = (int)((double)screen.GHeight / (screen.VCount + 2) + 0.5) - 1;
                }
                //重绘界面
                screen.RefreshScreen();
                if (isPrompt)
                {
                    screen.Prompt(screen.Finder.PathPointList);
                }
                //else
                //{
                //    if (screen.Finder.PathPointList.Count != 0)
                //    {
                //        screen.UnPrompt(screen.Finder.PathPointList);
                //    }
                //}
                if (preClick != -1)
                {
                    screen.Choose(preClick);
                }
            }
        }

        /// <summary>
        /// 游戏块自动对齐
        /// </summary>
        /// <param name="preClink"></param>
        /// <param name="curClick"></param>
        public void ChangeBlock(int preClink, int curClick)
        {
            int max = preClick > curClick ? preClick : curClick;
            int min = preClick < curClick ? preClick : curClick;
            //判断对齐方式
            switch (blockMode)
            {
                case BlockChangeMode.None:
                    {
                        break;
                    }
                case BlockChangeMode.Up:
                    {
                        int cur = max;
                        int exIndex = cur + screen.HCount;
                        while (exIndex <= screen.Stat.Length && screen.Stat[exIndex - 1] != 0)
                        {
                            screen.ExChange(cur, exIndex);
                            cur = exIndex;
                            exIndex = cur + screen.HCount;
                        }
                        cur = min;
                        exIndex = cur + screen.HCount;
                        while (exIndex <= screen.Stat.Length && screen.Stat[exIndex - 1] != 0)
                        {
                            screen.ExChange(cur, exIndex);
                            cur = exIndex;
                            exIndex = cur + screen.HCount;
                        }
                        break;
                    }
                case BlockChangeMode.Right:
                    {
                        int cur = min;
                        int exIndex = cur - 1;
                        int step = exIndex % screen.HCount;
                        while (step > 0 && screen.Stat[exIndex - 1] != 0)
                        {
                            screen.ExChange(cur, exIndex);
                            cur = exIndex;
                            exIndex = cur - 1;
                            step--;
                        }
                        cur = max;
                        exIndex = cur - 1;
                        step = exIndex % screen.HCount;
                        while (step > 0 && screen.Stat[exIndex - 1] != 0)
                        {
                            screen.ExChange(cur, exIndex);
                            cur = exIndex;
                            exIndex = cur - 1;
                            step--;
                        }
                        break;
                    }
                case BlockChangeMode.Down:
                    {
                        int cur = min;
                        int exIndex = cur - screen.HCount;
                        while (exIndex > 0 && screen.Stat[exIndex - 1] != 0)
                        {
                            screen.ExChange(cur, exIndex);
                            cur = exIndex;
                            exIndex = cur - screen.HCount;
                        }
                        cur = max;
                        exIndex = cur - screen.HCount;
                        while (exIndex > 0 && screen.Stat[exIndex - 1] != 0)
                        {
                            screen.ExChange(cur, exIndex);
                            cur = exIndex;
                            exIndex = cur - screen.HCount;
                        }
                        break;
                    }
                case BlockChangeMode.Left:
                    {
                        int cur = max;
                        int exIndex = cur + 1;
                        if (cur % screen.HCount != 0)
                        {
                            int step = (cur / screen.HCount + 1) * screen.HCount - cur;
                            while (step > 0 && screen.Stat[exIndex - 1] != 0)
                            {
                                screen.ExChange(cur, exIndex);
                                cur = exIndex;
                                exIndex = cur + 1;
                                step--;
                            }
                        }
                        cur = min;
                        exIndex = cur + 1;
                        if (cur % screen.HCount != 0)
                        {
                            int step = (cur / screen.HCount + 1) * screen.HCount - cur;
                            while (step > 0 && screen.Stat[exIndex - 1] != 0)
                            {
                                screen.ExChange(cur, exIndex);
                                cur = exIndex;
                                exIndex = cur + 1;
                                step--;
                            }
                        }
                        break;
                    }
                default:
                    break;
            }
        }

        ///// <summary>
        ///// 控制屏幕下雪
        ///// </summary>
        //public void ShowSnow()
        //{
        //    screen.BackGround = BackSnow.Run((screen.BackGround));
        //}

        #endregion
        /// <summary>
        /// 初始化声音
        /// </summary>
        private void InitSound()
        {
            try
            {
                string soundDir = "Sounds\\";
                spBg = new SoundPlayer(soundDir + "bg.mid", "bg");
                spErase = new SoundPlayer(soundDir + "Earse.wav", "earse");
                spRefresh = new SoundPlayer(soundDir + "refresh.wav", "refresh");
                spSelect = new SoundPlayer(soundDir + "select.wav", "select");
                spHint = new SoundPlayer(soundDir + "hint.wav", "hint");
            }
            catch
            {
                throw new Exception("无法加载声音，游戏初始化失败！");
            }
        }
        #region field and property

        private Grid screen;
        /// <summary>
        /// 游戏界面
        /// </summary>
        internal Grid Screen
        {
            get { return screen; }
            set { screen = value; }
        }
        private int gTime;
        /// <summary>
        /// 游戏总时间
        /// </summary>
        public int GTime
        {
            get { return gTime; }
            set { gTime = value; }
        }
        private int preClick;
        /// <summary>
        /// 单击选择的游戏网格块索引号
        /// </summary>
        internal int PreClick
        {
            get { return preClick; }
            set { preClick = value; }
        }
        private int curClick;
        /// <summary>
        /// 当前选中的游戏网格块索引号
        /// </summary>
        internal int CurClick
        {
            get { return curClick; }
            set { curClick = value; }
        }
        private GameState state;
        /// <summary>
        /// 游戏状态
        /// </summary>
        public GameState State
        {
            get { return state; }
            set { state = value; }
        }
        private GameLevel gLevel;
        /// <summary>
        /// 游戏难度
        /// </summary>
        public GameLevel GLevel
        {
            get { return gLevel; }
            set { gLevel = value; }
        }
        public int TotalGrid
        {
            get { return screen.VCount * screen.HCount; }
        }
        private int remain;
        /// <summary>
        /// 剩余块数
        /// </summary>
        public int Remain
        {
            get { return remain; }
            set { remain = value; }
        }
        private int totalScore;
        /// <summary>
        /// 总得分
        /// </summary>
        public int TotalScore
        {
            get { return totalScore; }
            set { totalScore = value; }
        }
        private int multiple;
        /// <summary>
        /// 积分倍数
        /// </summary>
        public int Multiple
        {
            get { return multiple; }
            set { multiple = value; }
        }
        private int promptNum;
        /// <summary>
        /// 提示数
        /// </summary>
        public int PromptNum
        {
            get { return promptNum; }
            set { promptNum = value; }
        }
        private int pause;
        /// <summary>
        /// 暂停数
        /// </summary>
        public int Pause
        {
            get { return pause; }
            set { pause = value; }
        }
        private bool isPrompt;
        /// <summary>
        /// 提示块对
        /// </summary>
        public bool IsPrompt
        {
            get { return isPrompt; }
            set { isPrompt = value; }
        }
        private bool isPlaySound;
        /// <summary>
        /// 是否播放音效
        /// </summary>
        public bool IsPlaySound
        {
            get { return isPlaySound; }
            set { isPlaySound = value; }
        }
        //声音对象
        private SoundPlayer spBg;
        private SoundPlayer spErase;
        private SoundPlayer spRefresh;
        private SoundPlayer spSelect;
        private SoundPlayer spHint;

        //产生积分倍数随机数
        private Random multiRan;
        private BlockChangeMode blockMode;
        private XmlRW xml;

        #endregion
    }
}
